import tkinter as tk
from tkinter import ttk, messagebox
import cv2
import numpy as np
from PIL import Image, ImageTk
import threading
import time
from collections import deque
import queue
from image_provider import ImageProvider
from logger import setup_logger

logger = setup_logger()

class RealtimeImageViewer:
    """实时图像显示器 - 直接显示原始图像"""
    
    def __init__(self, max_fps=30):
        """
        初始化实时图像显示器
        
        Args:
            max_fps: 最大帧率限制
        """
        self.max_fps = max_fps
        self.frame_interval = 1.0 / max_fps  # 帧间隔
        
        # 创建主窗口
        self.root = tk.Tk()
        self.root.title("实时图像显示器")
        self.root.geometry("1400x800")
        self.root.configure(bg='#2e2e2e')
        
        # 设置窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 初始化组件
        self.image_provider = None
        
        # 线程控制
        self.running = False
        self.image_thread = None
        
        # 图像数据队列
        self.image_queue = queue.Queue(maxsize=3)  # 减小队列防止延迟
        
        # 性能监控
        self.frame_times = deque(maxlen=30)
        self.get_times = deque(maxlen=30)
        
        # 统计信息
        self.total_frames = 0
        self.start_time = time.time()
        
        # 创建界面
        self.create_widgets()
        
        # 启动界面更新
        self.update_display()
        
    def create_widgets(self):
        """创建界面组件"""
        # 创建主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 控制面板
        control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 按钮区域
        button_frame = ttk.Frame(control_frame)
        button_frame.pack(fill=tk.X)
        
        # 开始/停止按钮
        self.start_button = ttk.Button(button_frame, text="开始", command=self.start_capture)
        self.start_button.pack(side=tk.LEFT, padx=(0, 10))
        
        self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_capture, state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT, padx=(0, 10))
        
        # 设置按钮
        self.settings_button = ttk.Button(button_frame, text="设置FPS", command=self.show_settings)
        self.settings_button.pack(side=tk.LEFT, padx=(0, 10))
        
        # 保存按钮
        self.save_button = ttk.Button(button_frame, text="保存当前帧", command=self.save_current_frame)
        self.save_button.pack(side=tk.LEFT, padx=(0, 10))
        
        # 状态标签
        self.status_label = ttk.Label(button_frame, text="状态: 已停止", foreground="red")
        self.status_label.pack(side=tk.RIGHT)
        
        # 性能信息面板
        perf_frame = ttk.LabelFrame(main_frame, text="性能信息", padding=10)
        perf_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 性能信息布局
        perf_grid = ttk.Frame(perf_frame)
        perf_grid.pack(fill=tk.X)
        
        # FPS显示
        ttk.Label(perf_grid, text="显示FPS:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
        self.fps_label = ttk.Label(perf_grid, text="0.0", foreground="blue", font=("Arial", 10, "bold"))
        self.fps_label.grid(row=0, column=1, sticky=tk.W, padx=(0, 20))
        
        # 获取图像时间
        ttk.Label(perf_grid, text="获取图像:").grid(row=0, column=2, sticky=tk.W, padx=(0, 5))
        self.get_time_label = ttk.Label(perf_grid, text="0.0ms")
        self.get_time_label.grid(row=0, column=3, sticky=tk.W, padx=(0, 20))
        
        # 图像尺寸
        ttk.Label(perf_grid, text="图像尺寸:").grid(row=0, column=4, sticky=tk.W, padx=(0, 5))
        self.size_label = ttk.Label(perf_grid, text="0x0")
        self.size_label.grid(row=0, column=5, sticky=tk.W, padx=(0, 20))
        
        # 总帧数
        ttk.Label(perf_grid, text="总帧数:").grid(row=1, column=0, sticky=tk.W, padx=(0, 5))
        self.frame_count_label = ttk.Label(perf_grid, text="0")
        self.frame_count_label.grid(row=1, column=1, sticky=tk.W, padx=(0, 20))
        
        # 运行时间
        ttk.Label(perf_grid, text="运行时间:").grid(row=1, column=2, sticky=tk.W, padx=(0, 5))
        self.runtime_label = ttk.Label(perf_grid, text="00:00:00")
        self.runtime_label.grid(row=1, column=3, sticky=tk.W, padx=(0, 20))
        
        # 队列状态
        ttk.Label(perf_grid, text="队列:").grid(row=1, column=4, sticky=tk.W, padx=(0, 5))
        self.queue_label = ttk.Label(perf_grid, text="0/3")
        self.queue_label.grid(row=1, column=5, sticky=tk.W)
        
        # 图像显示区域
        image_frame = ttk.LabelFrame(main_frame, text="图像显示", padding=5)
        image_frame.pack(fill=tk.BOTH, expand=True)
        
        # 图像画布
        self.canvas = tk.Canvas(image_frame, bg='black', highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 当前显示的图像
        self.current_image = None
        self.current_photo = None
        
    def show_settings(self):
        """显示FPS设置对话框"""
        settings_window = tk.Toplevel(self.root)
        settings_window.title("FPS设置")
        settings_window.geometry("300x150")
        settings_window.transient(self.root)
        settings_window.grab_set()
        
        # 居中显示
        settings_window.geometry("+%d+%d" % (
            self.root.winfo_rootx() + 50,
            self.root.winfo_rooty() + 50
        ))
        
        ttk.Label(settings_window, text="最大FPS限制:").pack(pady=20)
        
        fps_var = tk.StringVar(value=str(self.max_fps))
        fps_entry = ttk.Entry(settings_window, textvariable=fps_var, justify='center')
        fps_entry.pack(pady=10)
        fps_entry.focus()
        
        def apply_settings():
            try:
                new_fps = float(fps_var.get())
                if 1 <= new_fps <= 120:
                    self.max_fps = new_fps
                    self.frame_interval = 1.0 / new_fps
                    messagebox.showinfo("设置", f"FPS已设置为: {new_fps}")
                    settings_window.destroy()
                else:
                    messagebox.showerror("错误", "FPS值必须在1-120之间")
            except ValueError:
                messagebox.showerror("错误", "请输入有效的数字")
        
        def on_enter(event):
            apply_settings()
        
        fps_entry.bind('<Return>', on_enter)
        
        button_frame = ttk.Frame(settings_window)
        button_frame.pack(pady=10)
        
        ttk.Button(button_frame, text="应用", command=apply_settings).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="取消", command=settings_window.destroy).pack(side=tk.LEFT, padx=5)
        
    def save_current_frame(self):
        """保存当前帧"""
        if self.current_image is not None:
            timestamp = time.strftime("%Y%m%d_%H%M%S")
            filename = f"saved_frame_{timestamp}.png"
            cv2.imwrite(filename, self.current_image)
            messagebox.showinfo("保存", f"当前帧已保存为: {filename}")
            logger.info(f"保存图像: {filename}")
        else:
            messagebox.showwarning("警告", "没有可保存的图像")
    
    def start_capture(self):
        """开始捕获图像"""
        if self.running:
            return
            
        try:
            # 初始化图像提供器
            self.image_provider = ImageProvider(from_folder=False)
            
            # 启动图像捕获线程
            self.running = True
            self.image_thread = threading.Thread(target=self.image_capture_loop, daemon=True)
            self.image_thread.start()
            
            # 更新界面
            self.start_button.config(state=tk.DISABLED)
            self.stop_button.config(state=tk.NORMAL)
            self.status_label.config(text="状态: 运行中", foreground="green")
            
            # 重置统计
            self.total_frames = 0
            self.start_time = time.time()
            self.frame_times.clear()
            self.get_times.clear()
            
            # 清空队列
            while not self.image_queue.empty():
                try:
                    self.image_queue.get_nowait()
                except queue.Empty:
                    break
            
            logger.info("图像捕获已开始")
            
        except Exception as e:
            messagebox.showerror("错误", f"启动失败: {str(e)}")
            logger.error(f"启动图像捕获失败: {e}")
    
    def stop_capture(self):
        """停止捕获图像"""
        self.running = False
        
        if self.image_thread:
            self.image_thread.join(timeout=2.0)
        
        # 更新界面
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.status_label.config(text="状态: 已停止", foreground="red")
        
        logger.info("图像捕获已停止")
    
    def image_capture_loop(self):
        """图像捕获循环（在单独线程中运行）"""
        last_frame_time = 0
        
        while self.running:
            try:
                # 控制帧率
                current_time = time.time()
                if current_time - last_frame_time < self.frame_interval:
                    time.sleep(0.001)  # 短暂休眠
                    continue
                
                # 获取图像
                start = time.perf_counter()
                image_data = self.image_provider.get_next_image()
                get_time = time.perf_counter() - start
                
                if image_data is None or image_data.color_img is None:
                    time.sleep(0.01)  # 避免空转
                    continue
                
                # 记录日志
                logger.info(f"获取图像耗时: {get_time*1000:.1f}ms")
                
                # 将图像放入队列（如果队列满了，丢弃旧图像）
                if self.image_queue.full():
                    try:
                        self.image_queue.get_nowait()  # 移除最旧的图像
                    except queue.Empty:
                        pass
                
                self.image_queue.put({
                    'image': image_data.color_img.copy(),  # 复制图像避免引用问题
                    'get_time': get_time,
                    'timestamp': image_data.readable_timestamp
                })
                
                last_frame_time = current_time
                
            except Exception as e:
                logger.error(f"图像捕获循环错误: {e}")
                if not self.running:
                    break
                time.sleep(0.1)
    
    def update_display(self):
        """更新显示（在主线程中运行）"""
        try:
            # 处理队列中的图像
            processed_count = 0
            while not self.image_queue.empty() and processed_count < 2:  # 限制每次处理的图像数量
                try:
                    data = self.image_queue.get_nowait()
                    self.display_image(data['image'])
                    
                    # 更新性能统计
                    self.get_times.append(data['get_time'])
                    
                    current_time = time.time()
                    if len(self.frame_times) > 0:
                        frame_interval = current_time - self.last_display_time
                        self.frame_times.append(frame_interval)
                    
                    self.last_display_time = current_time
                    self.total_frames += 1
                    processed_count += 1
                    
                except queue.Empty:
                    break
            
            # 更新性能显示
            self.update_performance_display()
            
        except Exception as e:
            logger.error(f"显示更新错误: {e}")
        
        # 继续更新（约60fps的界面更新频率）
        self.root.after(16, self.update_display)
    
    def display_image(self, cv_image):
        """在画布上显示图像"""
        if cv_image is None:
            return
        
        try:
            # 保存当前图像
            self.current_image = cv_image
            
            # 获取图像信息
            height, width = cv_image.shape[:2]
            
            # 转换颜色格式（BGR -> RGB）
            if len(cv_image.shape) == 3:
                rgb_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
            else:
                rgb_image = cv_image
            
            # 转换为PIL图像
            pil_image = Image.fromarray(rgb_image)
            
            # 获取画布尺寸
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            
            if canvas_width > 1 and canvas_height > 1:
                # 计算缩放比例以适应画布（保持宽高比）
                scale_w = canvas_width / width
                scale_h = canvas_height / height
                scale = min(scale_w, scale_h, 1.0)  # 不放大，只缩小
                
                # 调整图像大小
                if scale < 1.0:
                    new_width = int(width * scale)
                    new_height = int(height * scale)
                    pil_image = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS)
            
            # 转换为Tkinter图像
            self.current_photo = ImageTk.PhotoImage(pil_image)
            
            # 清空画布并显示图像
            self.canvas.delete("all")
            
            # 居中显示
            img_width, img_height = pil_image.size
            x = (canvas_width - img_width) // 2
            y = (canvas_height - img_height) // 2
            self.canvas.create_image(x, y, anchor=tk.NW, image=self.current_photo)
            
            # 更新图像尺寸显示
            self.size_label.config(text=f"{width}x{height}")
            
        except Exception as e:
            logger.error(f"显示图像错误: {e}")
    
    def update_performance_display(self):
        """更新性能显示"""
        try:
            # 计算显示FPS
            if len(self.frame_times) > 1:
                avg_frame_time = sum(self.frame_times) / len(self.frame_times)
                fps = 1.0 / max(avg_frame_time, 1e-6)
                self.fps_label.config(text=f"{fps:.1f}")
                
                # 根据FPS设置颜色
                if fps >= 25:
                    self.fps_label.config(foreground="green")
                elif fps >= 15:
                    self.fps_label.config(foreground="orange")
                else:
                    self.fps_label.config(foreground="red")
            
            # 计算平均获取时间
            if len(self.get_times) > 0:
                avg_get_time = sum(self.get_times) / len(self.get_times)
                self.get_time_label.config(text=f"{avg_get_time*1000:.1f}ms")
                
                # 根据获取时间设置颜色
                if avg_get_time < 0.02:  # < 20ms
                    self.get_time_label.config(foreground="green")
                elif avg_get_time < 0.05:  # < 50ms
                    self.get_time_label.config(foreground="orange")
                else:
                    self.get_time_label.config(foreground="red")
            
            # 更新总帧数
            self.frame_count_label.config(text=str(self.total_frames))
            
            # 更新运行时间
            if self.running:
                runtime = time.time() - self.start_time
                hours = int(runtime // 3600)
                minutes = int((runtime % 3600) // 60)
                seconds = int(runtime % 60)
                self.runtime_label.config(text=f"{hours:02d}:{minutes:02d}:{seconds:02d}")
            
            # 更新队列状态
            queue_size = self.image_queue.qsize()
            self.queue_label.config(text=f"{queue_size}/3")
            
            # 根据队列状态改变颜色
            if queue_size >= 3:
                self.queue_label.config(foreground="red")
            elif queue_size >= 2:
                self.queue_label.config(foreground="orange")
            else:
                self.queue_label.config(foreground="green")
                
        except Exception as e:
            logger.error(f"性能显示更新错误: {e}")
    
    def on_closing(self):
        """窗口关闭事件"""
        if self.running:
            self.stop_capture()
        
        logger.info("窗口关闭，退出程序")
        self.root.destroy()
    
    def run(self):
        """运行应用程序"""
        try:
            # 初始化显示时间
            self.last_display_time = time.time()
            
            logger.info("启动Tkinter实时图像显示器")
            self.root.mainloop()
        except Exception as e:
            logger.error(f"应用程序运行错误: {e}")
        finally:
            logger.info("应用程序已退出")


# 极简版本 - 最基本的显示功能
class SimpleImageViewer:
    """极简图像显示器 - 只显示图像"""
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("简单图像显示器")
        self.root.geometry("1280x720")
        self.root.configure(bg='black')
        
        # 创建画布（全屏显示）
        self.canvas = tk.Canvas(self.root, bg='black', highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 简单控制
        self.root.bind('<space>', self.toggle)  # 空格键切换开始/停止
        self.root.bind('<s>', self.save_frame)  # S键保存
        self.root.bind('<Escape>', self.quit)   # ESC键退出
        
        # 状态
        self.running = False
        self.image_provider = None
        self.current_image = None
        
        # 在窗口上显示提示
        self.show_help()
        
    def show_help(self):
        """显示帮助信息"""
        help_text = "空格键: 开始/停止    S键: 保存    ESC键: 退出"
        self.canvas.create_text(640, 360, text=help_text, fill="white", 
                               font=("Arial", 16), tags="help")
    
    def toggle(self, event=None):
        """切换开始/停止"""
        if self.running:
            self.stop()
        else:
            self.start()
    
    def start(self):
        """开始显示"""
        if not self.running:
            try:
                self.running = True
                self.image_provider = ImageProvider(from_folder=False)
                self.canvas.delete("help")  # 删除帮助文本
                self.update_loop()
                logger.info("简单显示器已开始")
            except Exception as e:
                logger.error(f"启动失败: {e}")
                self.running = False
    
    def stop(self):
        """停止显示"""
        self.running = False
        self.canvas.delete("all")
        self.show_help()
        logger.info("简单显示器已停止")
    
    def save_frame(self, event=None):
        """保存当前帧"""
        if self.current_image is not None:
            timestamp = time.strftime("%Y%m%d_%H%M%S")
            filename = f"simple_saved_{timestamp}.png"
            cv2.imwrite(filename, self.current_image)
            logger.info(f"保存图像: {filename}")
            
            # 显示保存提示
            self.canvas.create_text(640, 50, text=f"已保存: {filename}", 
                                   fill="green", font=("Arial", 12), tags="save_msg")
            self.root.after(2000, lambda: self.canvas.delete("save_msg"))
    
    def quit(self, event=None):
        """退出程序"""
        self.running = False
        self.root.destroy()
    
    def update_loop(self):
        """更新循环"""
        if self.running:
            try:
                # 获取并显示图像
                image_data = self.image_provider.get_next_image()
                if image_data and image_data.color_img is not None:
                    self.display_image(image_data.color_img)
                else:
                    print("error no image_data")
            except Exception as e:
                logger.error(f"更新错误: {e}")
            
            # 继续更新
            self.root.after(33, self.update_loop)  # 约30fps
    
    def display_image(self, cv_image):
        """显示图像"""
        try:
            self.current_image = cv_image
            
            # 转换格式
            rgb_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
            pil_image = Image.fromarray(rgb_image)
            
            # 缩放以适应窗口
            canvas_width = self.root.winfo_width()
            canvas_height = self.root.winfo_height()
            
            if canvas_width > 1 and canvas_height > 1:
                img_width, img_height = pil_image.size
                scale = min(canvas_width/img_width, canvas_height/img_height)
                
                if scale < 1.0:
                    new_size = (int(img_width*scale), int(img_height*scale))
                    pil_image = pil_image.resize(new_size, Image.Resampling.LANCZOS)
            
            # 显示
            self.current_photo = ImageTk.PhotoImage(pil_image)
            self.canvas.delete("image")
            self.canvas.create_image(canvas_width//2, canvas_height//2, 
                                   image=self.current_photo, tags="image")
            
        except Exception as e:
            logger.error(f"显示错误: {e}")
    
    def run(self):
        """运行"""
        self.root.mainloop()


def main():
    app = RealtimeImageViewer(max_fps=30)
    
    app.run()


if __name__ == "__main__":
    main()